package top.codedance.iotp.registy.distributed;

import com.alibaba.fastjson.JSONObject;
import top.codedance.iotp.common.entity.ServerMeta;
import top.codedance.iotp.common.util.HttpRequestUtil;
import top.codedance.iotp.registy.RegistryApplication;
import org.apache.log4j.Logger;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

public class TeamServer {
    private static Logger logger = RegistryApplication.getLogger(TeamServer.class);

    private static Map<String, Integer> hostCount = new HashMap<>();

    public TeamServer(){}

    public void run(){
        try {
            RegistryApplication.syslogInfo("Registy team server success");
            while (true) {
                Date d = new Date();
                DateFormat df = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
                logger.debug("------------------"+df.format(d)+"------------------");
                logger.debug("onlineRegists count: "+ RegistryApplication.onlineRegists.size());
                logger.debug("servers count: "+ RegistryApplication.servers.size());
                logger.debug("clients count: "+ RegistryApplication.clients.size());
                logger.debug("----------------------------------------------------");
                if (RegistryApplication.onlineRegists.size() > 1) {
                    Date d1 = new Date();
                    //判断主节点是否已不能正常工作，如果不正常就进行重新选举
                    if(!RegistryApplication.isMaster && d1.getTime() - RegistryApplication.syncLastTimestamp > 10*1000){
                        RegistryApplication.workerPool.submit(() -> {
                            JSONObject post;
                            logger.debug("开始选举");
                            RegistryApplication.isElectioning = true;
                            boolean assumeMaster = true;
                            for (int i = 0; i < RegistryApplication.onlineRegists.size(); i++) {
                                try {
                                    String currentRegist = RegistryApplication.onlineRegists.get(i);
                                    //过滤自身
                                    if (RegistryApplication.isLocalIp(currentRegist)) {
                                        continue;
                                    }
                                    JSONObject jsonObject = new JSONObject();
                                    jsonObject.put("id", RegistryApplication.bootTimestamp);
                                    post = HttpRequestUtil.post(currentRegist + "/rest/api/election", jsonObject.toJSONString());
                                    if ((int) post.get("status") == 200) {
                                        JSONObject data = post.getJSONObject("data");
                                        assumeMaster = data.getBooleanValue("alive");
                                        logger.debug(currentRegist + ": 返回" + assumeMaster);
                                    }
                                }catch (Exception ex){
                                    logger.debug(ex.getMessage());
                                }
                            }
                            RegistryApplication.isMaster = assumeMaster;
                            if(RegistryApplication.isMaster) {
                                for (int i = 0; i < RegistryApplication.onlineRegists.size(); i++) {
                                    try {
                                        String currentRegist = RegistryApplication.onlineRegists.get(i);
                                        //过滤自身
                                        if (RegistryApplication.isLocalIp(currentRegist)) {
                                            continue;
                                        }
                                        JSONObject jsonObject = new JSONObject();
                                        jsonObject.put("masterHost", RegistryApplication.visitUrl);
                                        post = HttpRequestUtil.post(currentRegist + "/rest/api/victory", jsonObject.toJSONString());
                                        if ((int) post.get("status") == 200) {
                                            JSONObject data = post.getJSONObject("data");
                                            boolean ack = data.getBooleanValue("ack");
                                            logger.debug(currentRegist + ": 返回确认信息" + ack);
                                        }
                                    }catch (Exception ex){
                                        logger.debug(ex.getMessage());
                                    }
                                }
                            }
                            RegistryApplication.isElectioning = false;
                            Date d2 = new Date();
                            RegistryApplication.syncLastTimestamp = d2.getTime();
                            logger.debug("选举结束");
                        });
                    }

                    //注册中心节点健康状态
                    if(RegistryApplication.isMaster && !RegistryApplication.isElectioning) {
                        RegistryApplication.workerPool.submit(() -> {
                            JSONObject post;
                            for (int i = 0; i < RegistryApplication.onlineRegists.size(); i++) {
                                logger.debug("检查注册中心节点健康状态");
                                try {
                                    String currentRegist = RegistryApplication.onlineRegists.get(i);
                                    //过滤自身
                                    if (RegistryApplication.isLocalIp(currentRegist)) {
                                        continue;
                                    }
                                    post = HttpRequestUtil.post(currentRegist + "/rest/api/healthy", "");
                                    if ((int) post.get("status") == 200) {
                                        JSONObject healthyObject = post.getJSONObject("data");
                                        if (!healthyObject.getBoolean("healthy")) {
                                            logger.debug("[" + currentRegist + "] is not healthy.");
                                        }
                                    }
                                } catch (Exception e1) {
                                    logger.debug(e1.getMessage());
                                }
                            }
                        });
                    }

                    //向从节点同步数据
                    if(RegistryApplication.isMaster && !RegistryApplication.isElectioning) {
                        RegistryApplication.workerPool.submit(() -> {
                            Set<Map.Entry<String, ServerMeta>> sentries;
                            Set<Map.Entry<String, String>> centries;
                            Iterator<Map.Entry<String, ServerMeta>> siterator;
                            Iterator<Map.Entry<String, String>> citerator;
                            Map.Entry<String, ServerMeta> snext;
                            Map.Entry<String, String> cnext;
                            JSONObject post;
                            for (int i = 0; i < RegistryApplication.onlineRegists.size(); i++) {
                                logger.debug(RegistryApplication.port + "：开始同步。");
                                String currentRegist = RegistryApplication.onlineRegists.get(i);
                                if (RegistryApplication.isLocalIp(currentRegist)) {
                                    continue;
                                }
                                if (!hostCount.containsKey(currentRegist)) {
                                    hostCount.put(currentRegist, 0);
                                }
                                JSONObject allJo = new JSONObject();
                                JSONObject serverJo = new JSONObject();
                                sentries = RegistryApplication.servers.entrySet();
                                siterator = sentries.iterator();
                                while (siterator.hasNext()) {
                                    snext = siterator.next();
                                    serverJo.put(snext.getKey(), snext.getValue().toString());
                                }
                                allJo.put("servers", serverJo);
                                JSONObject clientJo = new JSONObject();
                                centries = RegistryApplication.clients.entrySet();
                                citerator = centries.iterator();
                                while (citerator.hasNext()) {
                                    cnext = citerator.next();
                                    clientJo.put(cnext.getKey(), cnext.getValue());
                                }
                                allJo.put("clients", clientJo);
                                post = HttpRequestUtil.post(currentRegist + "/rest/api/registy/sync", allJo.toJSONString());
                                if (post.getIntValue("status") != 200) {
                                    post = HttpRequestUtil.post(currentRegist + "/rest/api/healthy", "");
                                    if (post.getIntValue("status") != 200) {
                                        //目前来看还不能把没有响应的注册中心节点删除，因为一但烣复不能再增加到列表，目前的成员是平等关系，主节点是通过选举得到的，所以在刚启动节点时是没有主节点之说的，也就没有把新启的节点注册到主节点之说
//                                hostCount.put(currentRegist, hostCount.get(currentRegist) + 1);
//                                if (hostCount.get(currentRegist) >= 10) {
//                                    try {
//                                        Application.onlineRegists.remove(currentRegist);
//                                        hostCount.put(currentRegist, 0);
//                                        logger.debug(Application.port + "： " + currentRegist + ": 无响应，从列表删除");
//                                    } catch (Exception e) {
//                                    }
//                                }
                                    }
                                }else{
                                    logger.debug(RegistryApplication.port + "：同步成功。");
                                }
                            }
                        });
                    }
                }else{
                    if(!RegistryApplication.isMaster) {
                        RegistryApplication.isMaster = true;
                    }
                }
                try {
                    Thread.sleep(5000);
                } catch (Exception ex) {}
            }
        } catch (Exception e) {
            logger.debug(e.getMessage());
        } finally {
            try {
                Thread.sleep(1000);
            } catch (Exception ex) {}
            run();
        }
    }
}
